﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;

namespace _11_FlyWeight
{
    /// <summary>
    /// 享元模式 
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //享元是一种结构型设计模式， 它允许你在消耗少量内存的情况下支持大量对象。
            var factory = new FlyweightFactory(
                   new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" },
                new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" },
                new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" },
                new Car { Company = "BMW", Model = "M5", Color = "red" },
                new Car { Company = "BMW", Model = "X6", Color = "white" }
                );
            factory.ListFlyweights();
            AddCarToPoliceDatabase(factory, new Car
            {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "BMW",
                Color = "red"
            });
            AddCarToPoliceDatabase(factory, new Car
            {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "X1",
                Color = "red"
            });
            factory.ListFlyweights();
            Console.ReadKey();
            //所以对于结果应该是6个对象，因为BMW，BMW，red已经存在，所以直接修改Car的Number，和Owner属性即可。
        }
        public static void AddCarToPoliceDatabase(FlyweightFactory factory, Car car)
        {
            Console.WriteLine("\nClient: Adding a car to database.");
            //对于一辆汽车来说，一般颜色，型号，公司是固定属性，一个人可能拥有多辆车
            var flyweight = factory.GetFlyweight(new Car
            {
                Color = car.Color,
                Model = car.Model,
                Company = car.Company
            });
            flyweight.Operation(car);
        }
    }
    public class Flyweight
    {
        private Car _sharedState;
        public Flyweight(Car car)
        {
            _sharedState = car;
        }
        public void Operation(Car uniqueState)
        {
            string s = JsonConvert.SerializeObject(_sharedState);
            string u = JsonConvert.SerializeObject(uniqueState);
            Console.WriteLine($"Flyweight: Displaying shared { s}and unique { u}state.");
        }
    }
    public class FlyweightFactory
    {
        private List<Tuple<Flyweight, string>> flyweights = new List<Tuple<Flyweight, string>>();
        public FlyweightFactory(params Car[] args)
        {
            foreach (var item in args)
            {
                flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(item), GetKey(item)));
            }
        }
        public string GetKey(Car key)
        {
            List<string> elements = new List<string>();
            elements.Add(key.Model);
            elements.Add(key.Color);
            elements.Add(key.Company);
            if (key.Owner != null && key.Number != null)
            {
                elements.Add(key.Number);
                elements.Add(key.Owner);
            }
            elements.Sort();
            return string.Join("_", elements);
        }
        public Flyweight GetFlyweight(Car sharedState)
        {
            string key = GetKey(sharedState);
            //检查是不是已经包含重复的Model，Color，Company
            if (flyweights.Where(t => t.Item2 == key).Count() == 0)
            {
                Console.WriteLine("FlyweightFactory: Can't find a flyweight, creating new one.");
                flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(sharedState), key));
            }
            else
            {
                Console.WriteLine("FlyweightFactory:Reusing existing flyweight");
            }
            return flyweights.Where(t => t.Item2 == key).FirstOrDefault().Item1;
        }
        public void ListFlyweights()
        {
            var count = flyweights.Count;
            Console.WriteLine($"\nFlyweightFactory: I have {count} flyweights:");
            foreach (var flyweight in flyweights)
            {
                Console.WriteLine(flyweight.Item2);
            }
        }
    }

    public class Car
    {
        /// <summary>
        /// 拥有者
        /// </summary>
        public string Owner { get; set; }
        /// <summary>
        /// 编号
        /// </summary>
        public string Number { get; set; }
        /// <summary>
        /// 所属公司
        /// </summary>
        public string Company { get; set; }
        /// <summary>
        /// 型号
        /// </summary>
        public string Model { get; set; }
        /// <summary>
        /// 颜色
        /// </summary>
        public string Color { get; set; }
    }
}
